﻿using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Anderson.Utils.UI
{
    public enum TabKeySwitchMode
    {
        Manual,
        AutoScan
    }

    public class TabKeySwitcher : MonoBehaviour
    {
        #region Inspector
        [Header("Global")]
        public TabKeySwitchMode TabKeySwitcherMode = TabKeySwitchMode.AutoScan;
        public bool AutoSelectFirst = false;
        public bool SetHighlightedColor = true;
        public Color HighlightedColor = Color.grey;

        [Header("AutoScan")]
        public List<RectTransform> ScanTargets;
        [Header("Manual")]
        public List<Selectable> ManualTargets;
        #endregion

        #region Fields
        private Dictionary<int, Selectable> AllSelectableDict = new Dictionary<int, Selectable>();
        private int CurrentSelectIndex = -1;
        #endregion

        #region 对外公布的方法，方便其他输入系统调用
        public void OnTab()
        {
            SelectNext();
        }

        public void OnShiftTab()
        {
            SelectPrev();
        }
        #endregion

        private Selectable GetNextSelectable()
        {
            Selectable item = null;

            CurrentSelectIndex++;
            if (CurrentSelectIndex >= AllSelectableDict.Count)
            {
                CurrentSelectIndex = 0;
            }

            if (AllSelectableDict.ContainsKey(CurrentSelectIndex))
            {
                item = AllSelectableDict[CurrentSelectIndex];
            }

            return item;
        }

        private Selectable GetPrevSelectable()
        {
            Selectable item = null;

            CurrentSelectIndex--;
            if (CurrentSelectIndex < 0)
            {
                CurrentSelectIndex = AllSelectableDict.Count - 1;
            }

            if (AllSelectableDict.ContainsKey(CurrentSelectIndex))
            {
                item = AllSelectableDict[CurrentSelectIndex];
            }

            return item;
        }

        // Use this for initialization
        void Start()
        {
            InitAllSelectable();

            if (AutoSelectFirst)
            {
                SelectNext();
            }
        }

        private void SelectNext()
        {
            Selectable item = GetNextSelectable();
            if (null != item)
            {
                item.Select();
            }
        }

        private void SelectPrev()
        {
            Selectable item = GetPrevSelectable();
            if (null != item)
            {
                item.Select();
            }
        }

        private void InitAllSelectable()
        {
            List<Selectable> selectableList = new List<Selectable>();

            if (TabKeySwitcherMode == TabKeySwitchMode.Manual)
            {
                if (null != ManualTargets)
                {
                    foreach (Selectable c in ManualTargets)
                    {
                        if (!selectableList.Contains(c))
                        {
                            selectableList.Add(c);
                        }
                    }
                }
            }
            else
            {
                foreach (RectTransform item in ScanTargets)
                {
                    ScanSelectableToList(item, selectableList);
                }
            }

            AddToAllSelectable(selectableList);
        }

        private void ScanSelectableToList(RectTransform item, List<Selectable> selectableList)
        {
            if (null == item)
            {
                return;
            }

            Selectable[] children = item.GetComponentsInChildren<Selectable>();
            foreach (Selectable c in children)
            {
                if (!selectableList.Contains(c))
                {
                    selectableList.Add(c);
                }
            }
        }

        private void AddToAllSelectable(List<Selectable> selectableList)
        {
            if (null == selectableList)
            {
                return;
            }

            int existCount = AllSelectableDict.Count;
            foreach (Selectable item in selectableList)
            {
                //Debug.Log(string.Format("{0}, {1}", item.gameObject.name, item.GetType().Name));
                
                if (SetHighlightedColor && item.transition == Selectable.Transition.ColorTint)
                {
                    ColorBlock cb = item.colors;
                    cb.highlightedColor = HighlightedColor;
                    item.colors = cb;
                }

                AllSelectableDict.Add(existCount, item);

                existCount++;
            }
        }

        private void GetCurrentSelectable()
        {
            //get current selectable in eventsystem
            //set index
            GameObject go = EventSystem.current.currentSelectedGameObject;
            if (null == go)
            {
                CurrentSelectIndex = -1;

                return;
            }

            Selectable item = go.GetComponent<Selectable>();
            if (null == item)
            {
                //貌似不可能
                CurrentSelectIndex = -1;

                return;
            }

            KeyValuePair<int, Selectable> kvp = AllSelectableDict.Where((kv) => {
                return kv.Value == item;
            }).First();

            if (kvp.Value == null)
            {
                //貌似也不可能
                CurrentSelectIndex = -1;

                return;
            }

            CurrentSelectIndex = kvp.Key;
        }

        // Update is called once per frame
        void Update()
        {
            if (Input.GetKeyUp(KeyCode.Tab))
            {
                GetCurrentSelectable();

                if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                {
                    OnShiftTab();
                }
                else
                {
                    OnTab();
                }
            }
        }
                
    }

}